﻿using AutoMapper;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using Windows.Admin.Application.Dtos;
using Windows.Admin.Application.Service;
using Windows.Admin.Domain;
using Windows.Admin.Infrastructure;
using Windows.Admin.Infrastructure.EFCore;
using Windows.Admin.Infrastructure.EFCore.Extensions;
using Windows.Application.Share;
using Windows.FileStorage.Contract;
using Windows.Infrastructure.Share.Extensions;
using Windows.Infrastructure.Share.Security;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;

namespace Windows.Admin.Application
{
    public class ChatService : IChatService
    {
        private readonly IMapper _mapper;
        //private readonly ICache _cache;
        private readonly AdminDbContext _db;
        private readonly ICurrentUser _currentUser;
        private readonly IHubContext<InformHub> _hub;
        private readonly IAttachmentGrpcService _attachmentGrpcSvc;
        public ChatService(IMapper mapper, AdminDbContext db, ICurrentUser currentUser, IHubContext<InformHub> hub, IAttachmentGrpcService attachmentGrpcSvc)
        {
            _mapper = mapper;
            _db = db;
            _currentUser = currentUser;
            _hub = hub;
            _attachmentGrpcSvc = attachmentGrpcSvc;
        }
        /// <summary>
        /// 获取聊天列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<ChatLinkResponse>> GetChatLinks()
        {
            List<ChatLinkResponse> chatLinks =
                await (from c in _db.ChatLink.GetByUserId(_currentUser.Id)
                       from u1 in _db.User.Where(x => x.Id == c.UserId1)
                       from u2 in _db.User.Where(x => x.Id == c.UserId2)
                       from e1 in _db.Employee.Where(x => x.UserId == u1.Id).DefaultIfEmpty()
                       from e2 in _db.Employee.Where(x => x.UserId == u2.Id).DefaultIfEmpty()
                       from m in _db.ChatMessage.Where(x => x.ChatLinkId == c.Id && x.ReceiverId == _currentUser.Id && !x.IsRead).GroupBy(g => g.ChatLinkId).Select(s => new MessageNoRead { ChatId = s.Key, NoReadCount = s.Count() }).DefaultIfEmpty()
                       from m1 in _db.ChatMessage.Where(x => x.ChatLinkId == c.Id).OrderByDescending(x => x.ChatedOn).Take(1)
                       select new ChatLinkResponse
                       {
                           ChatId = c.Id,
                           EmployeeId = u1.Id != _currentUser.Id ? e1.Id : e2.Id,
                           UserId = u1.Id != _currentUser.Id ? u1.Id : u2.Id,
                           Name = u1.Id != _currentUser.Id ? e1 == null ? u1.UserName : e1.Name : e2 == null ? u2.UserName : e2.Name,
                           LastMessage = m1.Message,
                           LastChatedOn = m1.ChatedOn,
                           NoReadCount = m.NoReadCount == null ? 0 : m.NoReadCount.Value
                       }
             ).OrderByDescending(x => x.LastChatedOn).ToListAsync();

            GetAttachmentsByOwnerIdsRequest request = new();
            request.OwnerIds = chatLinks.Where(x => x.EmployeeId != null).Select(s => s.EmployeeId.Value).ToList();
            if (request.OwnerIds.Count() > 0)
            {

                var attachements = await _attachmentGrpcSvc.GetAttachmentsByOwnerIds(request);
                foreach (var l in chatLinks.Where(x => x.EmployeeId != null))
                {
                    l.AttachmentPath = attachements.Where(x => x.OwnerId == l.EmployeeId).Select(s => s.AttachmentPath).FirstOrDefault();
                }
            }
            return chatLinks;
        }
        /// <summary>
        /// 添加聊天
        /// </summary>
        /// <param name="employeeId"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task<ChatLinkResponse> AddChatLink(int employeeId)
        {
            Employee? employee = await _db.Employee.Include(x => x.User).FindByIdAsync(employeeId);
            if (employee == null)
            {
                throw new ApiException("此员工未绑定用户账号,暂不支持聊天!");
            }
            var chatLink = await _db.ChatLink.GetByTwoUserId(employee!.UserId!.Value, _currentUser.Id).FirstOrDefaultAsync();
            ChatMessage? lastChatMessage = null;
            if (chatLink == null)
            {
                chatLink = new ChatLink();
                chatLink.UserId1 = _currentUser.Id;
                chatLink.UserId2 = employee.UserId.Value;
                _db.ChatLink.Add(chatLink);
                await _db.SaveChangesAsync();
            }
            else
            {
                lastChatMessage = await _db.ChatMessage.Where(x=>x.ChatLinkId == chatLink.Id).FirstOrDefaultAsync();
            }
            ChatLinkResponse ChatLinkRes = new()
            {
                ChatId = chatLink.Id,
                EmployeeId = employee.Id,
                UserId = employee.UserId.Value,
                Name = employee.Name,
                LastMessage = lastChatMessage == null ? "" : lastChatMessage.Message,
                LastChatedOn = lastChatMessage == null ? null : lastChatMessage.ChatedOn,
                
            };
            AttachmentRequest request = new() 
            {
                OwnerId = employee.Id
            };
            AttachmentResponse? attachment = await _attachmentGrpcSvc.GetAttachment(request);
            if (attachment != null)
            {
                ChatLinkRes.AttachmentPath = attachment!.AttachmentPath!;
            }
            
            return ChatLinkRes;
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task SendMessageAsync(SendMessageRequest request)
        {
            ChatMessage chatMessage = new()
            {
                ChatLinkId = request.ChatLinkId,
                SenderId = _currentUser.Id,
                ReceiverId = request.ReceiverId,
                MessageType = request.MessageType,
                Message = request.Message,
                ChatedOn = DateTime.Now
            };
            await _db.ChatMessage.AddAsync(chatMessage);
            await _db.SaveChangesAsync();
            string connectionId = Common.LinkInfos.Where(x => x.Key == request.ReceiverId).FirstOrDefault().Value;
            if (connectionId != null)
            {
                var user = await _db.User.Include(x=>x.Employees).FindByIdAsync(chatMessage.ReceiverId);
                ChatMessageResponse res = new ChatMessageResponse();
                res.ChatLinkId = chatMessage.ChatLinkId;
                res.SenderId = chatMessage.SenderId;
                res.SenderName = _currentUser.Name;
                res.ReceiverId = chatMessage.ReceiverId;
                res.ReceiverName = user.Employees.Count >0 ? user.Employees.FirstOrDefault().Name : user.UserName;
                res.Message = chatMessage.Message;
                res.ChatedOn = chatMessage.ChatedOn;
                await _hub.Clients.Client(connectionId).SendAsync(method: MessageTypeEnum.NewMessage.ToString(), arg1: res);
            }
            
        }
        /// <summary>
        /// 获取chatId的聊天列表
        /// </summary>
        /// <param name="chatId"></param>
        /// <returns></returns>
        public async Task<List<ChatMessageResponse>> GetChatMessagesAsync(int chatId)
        {
            var list = await (
                                from m in _db.ChatMessage.Where(x => x.ChatLinkId == chatId)
                                from u1 in _db.User.Where(x => x.Id == m.SenderId)
                                from u2 in _db.User.Where(x => x.Id == m.ReceiverId)
                                from e1 in _db.Employee.Where(x => x.UserId == u1.Id).DefaultIfEmpty()
                                from e2 in _db.Employee.Where(x => x.UserId == u2.Id).DefaultIfEmpty()
                                select new ChatMessageResponse
                                {
                                    ChatLinkId = m.ChatLinkId,
                                    SenderId = m.SenderId,
                                    SenderName = e1 == null ? u1.UserName : e1.Name,
                                    ReceiverName = e2 == null ? u2.UserName : e2.Name,
                                    Message = m.Message,
                                    ChatedOn = m.ChatedOn,
                                }
             ).OrderBy(x => x.ChatedOn).ToListAsync();
            return list;
        }
        /// <summary>
        /// 信息设置已读
        /// </summary>
        /// <param name="chatId"></param>
        /// <returns></returns>
        public async Task SetChatMessageToReadAsync(int chatId)
        {
            var list = await _db.ChatMessage.Where(x => !x.IsRead && x.ChatLinkId == chatId && x.ReceiverId == _currentUser.Id).ToListAsync();
            list.ForEach(x => x.IsRead = true);
            await _db.SaveChangesAsync();
        }
    }
    public class MessageNoRead
    { 
        public long? ChatId { get; set; }
        public int? NoReadCount { get; set; }
    }
}
